package com.zzyl.nursing.service.impl;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;


import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.huaweicloud.sdk.iotda.v5.IoTDAClient;
import com.huaweicloud.sdk.iotda.v5.model.*;
import com.zzyl.common.constant.CacheConstants;
import com.zzyl.common.core.domain.AjaxResult;
import com.zzyl.common.utils.DateUtils;
import com.zzyl.nursing.dto.DeviceDto;
import com.zzyl.nursing.vo.DeviceDetailVo;
import com.zzyl.nursing.vo.ProductVo;
import net.sf.jsqlparser.expression.DateTimeLiteralExpression;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.zzyl.nursing.mapper.DeviceMapper;
import com.zzyl.nursing.domain.Device;
import com.zzyl.nursing.service.IDeviceService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

/**
 * 设备Service业务层处理
 *
 * @author alexis
 * @date 2025-09-22
 */
@Service
public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> implements IDeviceService {
    @Autowired
    private DeviceMapper deviceMapper;

    /**
     * 查询设备
     *
     * @param id 设备主键
     * @return 设备
     */
    @Override
    public Device selectDeviceById(Long id) {
        return deviceMapper.selectById(id);
    }

    /**
     * 查询设备列表
     *
     * @param device 设备
     * @return 设备
     */
    @Override
    public List<Device> selectDeviceList(Device device) {
        return deviceMapper.selectDeviceList(device);
    }

    /**
     * 新增设备
     *
     * @param device 设备
     * @return 结果
     */
    @Override
    public int insertDevice(Device device) {
        return deviceMapper.insert(device);
    }

    /**
     * 修改设备
     *
     * @param device 设备
     * @return 结果
     */
    @Override
    public int updateDevice(Device device) {
        return deviceMapper.updateById(device);
    }

    /**
     * 批量删除设备
     *
     * @param ids 需要删除的设备主键
     * @return 结果
     */
    @Override
    public int deleteDeviceByIds(Long[] ids) {
        return deviceMapper.deleteBatchIds(Arrays.asList(ids));
    }

    /**
     * 删除设备信息
     *
     * @param id 设备主键
     * @return 结果
     */
    @Override
    public int deleteDeviceById(Long id) {
        return deviceMapper.deleteById(id);
    }

    @Autowired
    private IoTDAClient client;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Override
    public void syncProductList() {
        ListProductsRequest request = new ListProductsRequest();
        ListProductsResponse response = client.listProducts(request);
        List<ProductSummary> products = response.getProducts();
        //将产品列表保存到redis中，key: iot:productList
        redisTemplate.opsForValue().set(CacheConstants.ALL_PRODUCT_LIST_KEY, JSONUtil.toJsonStr(products));
    }

    @Override
    public List<ProductVo> getAll() {
        //这里从redis中获取产品列表即可
        String jsonStr = redisTemplate.opsForValue().get(CacheConstants.ALL_PRODUCT_LIST_KEY);
        List<ProductVo> list = JSONUtil.toList(jsonStr, ProductVo.class);
        return list;
    }

    @Override
    public void register(DeviceDto dto) {
        //1. 首先判断一下设备名称是否重复
        /**
         * 这里和谁进行比较呢？既然要注册，应该是和数据库中已有的数据进行比较的
         */
        LambdaQueryWrapper<Device> lqw = new LambdaQueryWrapper<>();
        lqw.eq(Device::getDeviceName, dto.getDeviceName());
        long count = count(lqw);
        if (count > 0) {
            throw new RuntimeException("设备名称重复");
        }
        //2. 设备标识是否重复，设备标识其实就是nodeId
        //这里也是和数据库中已有的数据进行比较的
        lqw = new LambdaQueryWrapper<>();
        lqw.eq(Device::getNodeId, dto.getNodeId());
        count = count(lqw);
        if (count > 0) {
            throw new RuntimeException("设备标识重复");
        }
        //3.同一位置是否指定了相同的产品
        //这是指，一个产品，同一个老人，绑定同一个位置
        //只能有一个设备
        lqw = new LambdaQueryWrapper<>();
        lqw.eq(Device::getBindingLocation, dto.getBindingLocation())
                .eq(Device::getProductKey, dto.getProductKey())
                .eq(Device::getLocationType, dto.getLocationType())
                .eq(Device::getPhysicalLocationType, dto.getPhysicalLocationType());
        count = count(lqw);
        if (count > 0) {
            throw new RuntimeException("此位置已有相同设备绑定");
        }
        //4. 校验完毕，开始新增逻辑
        //注意这里的新增，要保存数据库和华为云两个地方
        ;
        AddDeviceRequest request = new AddDeviceRequest();
        AddDevice body = new AddDevice();
        body.withProductId(dto.getProductKey());
        body.withDeviceName(dto.getDeviceName());
        body.withNodeId(dto.getNodeId());
        AuthInfo authInfo = new AuthInfo();
        //秘钥
        String secret = UUID.randomUUID().toString().replaceAll("-", "");
        authInfo.withSecret(secret);
        body.setAuthInfo(authInfo);
        request.withBody(body);
        //判断一下这里是否发送成功
        String deviceId;
        try {
            AddDeviceResponse response = client.addDevice(request);
            deviceId = response.getDeviceId();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        //保存到数据库
        Device device = new Device();
        BeanUtils.copyProperties(dto, device);
        device.setIotId(deviceId);
        device.setSecret(secret);
//        deviceMapper.insertDevice(device);
        insertDevice(device);
//        save(device);

    }

    @Override
    public DeviceDetailVo queryDeviceDetail(String iotId) {
        //这里的任务是从华为云和数据库查询信息，补全一个vo的字段
        //使用条件构建器+getone的方式查询数据库
        LambdaQueryWrapper<Device> lqw = new LambdaQueryWrapper<>();
        lqw.eq(Device::getIotId, iotId);
        Device device = getOne(lqw);
        //创建一个vo对象
        DeviceDetailVo vo = new DeviceDetailVo();
        BeanUtils.copyProperties(device, vo);
        //这里发现创建时间我没有复制到vo中
        Date createTime = device.getCreateTime();
        LocalDateTime localDateTime = createTime.toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDateTime();
        vo.setCreateTime(localDateTime);
        //开始查询华为云补全字段
        ShowDeviceRequest request = new ShowDeviceRequest();
        request.withDeviceId(iotId);
        ShowDeviceResponse response = client.showDevice(request);
        vo.setDeviceStatus(response.getStatus());
        String activeTimeStr = response.getActiveTime();
        System.out.println("activeTimeStr:" + activeTimeStr);
        if (activeTimeStr != null && !activeTimeStr.isEmpty()) {
            // 解析 ISO 8601 格式的时间字符串
            ZonedDateTime zonedDateTime = ZonedDateTime.parse(activeTimeStr);
            // 转换为本地时间
            LocalDateTime activeTime = zonedDateTime.withZoneSameInstant(ZoneId.systemDefault()).toLocalDateTime();
            vo.setActiveTime(activeTime);
        } else {
            // 可以设置默认值或者保持为 null（取决于业务需求）
            vo.setActiveTime(null);
        }
        return vo;
    }

    @Override
    public AjaxResult queryServiceProperties(String iotId) {
        //先根据设备的id查询华为云的影子信息
        ShowDeviceShadowRequest request = new ShowDeviceShadowRequest();
        request.withDeviceId(iotId);
        ShowDeviceShadowResponse response = client.showDeviceShadow(request);
        //判断是否请求成功，不成功就报异常
        if (response.getHttpStatusCode() != 200) {
            throw new RuntimeException("请求失败");
        }
        //成功则获取影子数据,判断是否有数据
        List<DeviceShadowData> shadow = response.getShadow();
        if (CollUtil.isEmpty(shadow)) {
            List<Object> emptyList = Collections.emptyList();
            return AjaxResult.success(emptyList);
        }
        Map<String, Object> properties = (Map<String, Object>) shadow.get(0).getReported().getProperties();
        String eventTime = shadow.get(0).getReported().getEventTime();
        System.out.println("eventTime:" + eventTime);
        // 定义输入时间格式（UTC不带时区信息，但末尾的Z表示UTC）
        DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss'Z'");

        // 解析为UTC时区的时间
        ZonedDateTime utcTime = ZonedDateTime.parse(eventTime, inputFormatter.withZone(java.time.ZoneOffset.UTC));

        // 转换为东八区（Asia/Shanghai）时间
        ZonedDateTime cstTime = utcTime.withZoneSameInstant(java.time.ZoneId.of("Asia/Shanghai"));

        // 定义输出格式
        DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        // 格式化输出
        String resultTime = cstTime.format(outputFormatter);
        //新建一个List<Map>,用来封装返回给前端的数据
        List<Map<String, Object>> list = new ArrayList<>();
        properties.forEach((key, value) -> {
            HashMap<String, Object> result = new HashMap<>();
            result.put("functionId", key);
            result.put("value", value);
            result.put("eventTime", resultTime);
            list.add(result);
        });

        return AjaxResult.success(list);
    }


}
